package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.cart.service.CartInfoAsyncService;
import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.feign.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.redisson.misc.Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service
public class CartInfoServiceImpl implements CartInfoService {


    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;

    //查询刚刚加入的购物车


    //加入购物车
    @Override
    public CartInfo addToCart(Long skuId, Integer skuNum, String userId) {
        //如何保存购物车
        //1:先查询当前用户是否已经有购物车了 DB
        CartInfo cartInfo = cartInfoMapper.selectOne(new
                QueryWrapper<CartInfo>()
                .eq("user_id", userId)
                .eq("sku_id", skuId));
        if (cartInfo != null) {
            //此用户 已经加入过此商品了
            //追加商品的数量
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            // 选中
            cartInfo.setIsChecked(1);
            //更新购物车
            cartInfoMapper.updateById(cartInfo);
        } else {
            //插入一个新商品
            cartInfo = new CartInfo();
            //用户ID
            cartInfo.setUserId(userId);
            //数量
            cartInfo.setSkuNum(skuNum);
            //skuId
            cartInfo.setSkuId(skuId);

            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            //库存名称
            cartInfo.setSkuName(skuInfo.getSkuName());
            //图片
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            //价格
            cartInfo.setCartPrice(skuInfo.getPrice());

            cartInfoMapper.insert(cartInfo);
        }
        //实实价格
        cartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
        //手动将当前购物车放到Redis缓存中
        redisTemplate.opsForHash().put(RedisConst.USER_KEY_PREFIX + userId
                + RedisConst.USER_CART_KEY_SUFFIX, skuId.toString(), cartInfo);
        //redisTemplate.expire(userId,7, TimeUnit.DAYS);
        return cartInfo;
    }

    // //去购物车结算  为了查询当前用户的所有购物车
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        //1:判断真实用户是否存在
        if (!StringUtils.isEmpty(userId)) {
            //登录了
            if (!StringUtils.isEmpty(userTempId)) {
                //继续查询真实用户及临时用户的购物车集合 并且合并起来
                return getMergeCartInfoList(userId, userTempId);

            } else {
                //有真实用户 没有临时用户
                return getCartInfoList(userId);
            }
        } else {
            //未登录 判断临时用户是否存在
            if (!StringUtils.isEmpty(userTempId)) {
                //继续查询临时用户的购物车集合
                return getCartInfoList(userTempId);
            }
        }
        //临时及真实都没有
        return null;
    }

    //选中
    @Override
    @Transactional(rollbackFor = Throwable.class) //默认情况只有在RuntimeException及子异常的时候才会回滚
    // 事务管理器(切面）去连接DB  transaction start
    public void checkCart(Long skuId, Integer isChecked) {
        //获取用户ID
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isEmpty(userId)) {
            userId = AuthContextHolder.getUserTempId(request);
        }
        //更新选中项
        CartInfo cartInfo = new CartInfo();
        cartInfo.setIsChecked(isChecked);
        //参数1：更新的字段  update cart_info set 参数1
        //参数2：条件   where  参数2
        cartInfoMapper.update(cartInfo, new QueryWrapper<CartInfo>().
                eq("user_id", userId).eq("sku_id", skuId));
        //事务：更新DB的同时  更新Redis  要求事务
        //更新缓存
        String cacheKey = RedisConst.USER_KEY_PREFIX + userId
                + RedisConst.USER_CART_KEY_SUFFIX;
        cartInfo = (CartInfo) redisTemplate.opsForHash().get(cacheKey, skuId.toString());
        cartInfo.setIsChecked(isChecked);
        redisTemplate.opsForHash().put(cacheKey, skuId.toString(), cartInfo);
    }
    // 事务管理器(切面）去连接DB  rollback
    // 事务： 前置 transaction start    后置  返回值 commit  异常  rollback

    @Autowired
    private CartInfoAsyncService cartInfoAsyncService;

    //删除购物车
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void deleteCart(Long skuId) {
        //获取用户ID
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isEmpty(userId)) {
            userId = AuthContextHolder.getUserTempId(request);
        }

        System.out.println("deleteCart：" + Thread.currentThread().getName());
        //1:DB 删除
        cartInfoAsyncService.deleteDB(skuId, userId);
        //2:redis 删除
        String cacheKey = RedisConst.USER_KEY_PREFIX + userId
                + RedisConst.USER_CART_KEY_SUFFIX;
        redisTemplate.opsForHash().delete(cacheKey, skuId.toString());
    }

    //查询刚刚加入的购物车   临时用户
    @Override
    public CartInfo getCartInfo(Long skuId, String userId) {
        String cacheKey = RedisConst.USER_KEY_PREFIX + userId
                + RedisConst.USER_CART_KEY_SUFFIX;
        return (CartInfo) redisTemplate.opsForHash().get(cacheKey, skuId.toString());
    }

    //获取 购物车集合（选中的）
    @Override
    public List<CartInfo> findCartInfoListByChecked(String userId) {
        //1:从Redis缓存中获取出已经选中
        //2:从DB中数据
        List<CartInfo> cartInfoList = cartInfoMapper.selectList(new QueryWrapper<CartInfo>()
                .eq("user_id", userId).eq("is_checked", 1));
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            cartInfoList.stream().peek(cartInfo -> {
                cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
            }).collect(Collectors.toList());
        }
        return cartInfoList;
    }

    //查询真实用户及临时用户的购物车集合 并且合并起来    已经登录 以真实为准 即使真实为购物车0
    private List<CartInfo> getMergeCartInfoList(String userId, String userTempId) {
        //真实用户的购物车集合
        List<CartInfo> cartInfoListByUserId = getCartInfoList(userId);
        //临时用户的购物车集合
        List<CartInfo> cartInfoListByUserTempId = getCartInfoList(userTempId);

        //判断真实用户的购物车集合是否存在
        if (CollectionUtils.isEmpty(cartInfoListByUserId)) {
            cartInfoListByUserId = new ArrayList<>();
        }
        //判断临时用户的购物车集合是否存在
        if (!CollectionUtils.isEmpty(cartInfoListByUserTempId)) {
            // List<CartInfo> ==> stream 流 转成Map<skuId,CartInfo>
            Map<Long, CartInfo> mapByUserId = cartInfoListByUserId.stream().collect(
                    Collectors.toMap(CartInfo::getSkuId, cartInfo -> {
                        return cartInfo;
                    }));
            //真实用户的购物车集合 临时也有  合并
            for (CartInfo cartInfoByUserTempId : cartInfoListByUserTempId) {
                //1:临时购物车在真实购物车集合中是否已经存在了
                CartInfo cartInfoByUserId = mapByUserId.
                        get(cartInfoByUserTempId.getSkuId());
                if (null != cartInfoByUserId) {
                    //2:存在了 追加数量
                    cartInfoByUserId.setSkuNum(cartInfoByUserId.getSkuNum() +
                            cartInfoByUserTempId.getSkuNum());
                    //选中
                    cartInfoByUserId.setIsChecked(1);
                    //DB要更新
                    cartInfoMapper.updateById(cartInfoByUserId);
                    //删除临时信息
                    cartInfoMapper.deleteById(cartInfoByUserTempId.getId());
                } else {
                    //3:不存在 新购物车追加进去
                    mapByUserId.put(cartInfoByUserTempId.getSkuId(), cartInfoByUserTempId);
                    //更新用户ID
                    cartInfoByUserTempId.setUserId(userId);
                    cartInfoMapper.updateById(cartInfoByUserTempId);
                }
            }
            String cacheKeyByUserId = RedisConst.USER_KEY_PREFIX + userId
                    + RedisConst.USER_CART_KEY_SUFFIX;
            String cacheKeyByUserTempId = RedisConst.USER_KEY_PREFIX + userTempId
                    + RedisConst.USER_CART_KEY_SUFFIX;
            //删除真实用户的缓存
            redisTemplate.delete(cacheKeyByUserId);
            //删除临时用户的缓存
            redisTemplate.delete(cacheKeyByUserTempId);
            //上面循环结束
            return new ArrayList<>(mapByUserId.values());
        } else {
            //没有临时用户的购物车集合
            return cartInfoListByUserId;
        }
    }

    //根据用户ID查询购物车集合
    private List<CartInfo> getCartInfoList(String userId) {
        String cacheKey = RedisConst.USER_KEY_PREFIX + userId
                + RedisConst.USER_CART_KEY_SUFFIX;
        //1:优先查询Redis   中购物车集
        List<CartInfo> cartInfoList = redisTemplate.opsForHash()
                .values(cacheKey);

        if (CollectionUtils.isEmpty(cartInfoList)) {
            //2 ： 没有 再查询DB
            cartInfoList = cartInfoMapper.selectList(new QueryWrapper<CartInfo>()
                    .eq("user_id", userId));

            //3: 保存一份在Redis中
            if (!CollectionUtils.isEmpty(cartInfoList)) {
                //替换掉之前的集合
                cartInfoList = cartInfoList.stream().peek(cartInfo -> {
                    //实实价格
                    cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
                    //return cartInfo;
                }).collect(Collectors.toList());
                //List<CartInfo>  ==>  Map<skuId,CartInfo>  首页 一二三级分类
                Map<String, CartInfo> map = cartInfoList.stream().collect(
                        Collectors.toMap(cartInfo -> {
                            return cartInfo.getSkuId().toString();
                        }, cartInfo -> {
                            return cartInfo;
                        }));
                redisTemplate.opsForHash().putAll(cacheKey, map);
            }
        }
        //排序
        cartInfoList = cartInfoList.stream().sorted((cartInfo1, cartInfo2) -> {
            Long i = cartInfo2.getId() - cartInfo1.getId();
            return i.intValue();
        }).collect(Collectors.toList());
        return cartInfoList;
    }
}
